<?php
/**
 * RedisCluster k-v缓存操作类
 * @author chunyang.shu
 * @date 2017-02-08
 */
include_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'np_kv_cache.class.php';
class np_kv_cache_redis_cluster_class extends np_kv_cache_class
{
	/**
	 * 连接超时时间
	 * @var int
	 */
	private $int_connect_timeout = 20;
	
	/**
	 * 查询超时时间
	 * @var int
	 */
	private $int_query_timeout = 20;
	
	/**
	 * 配置信息
	 * @var array
	 */
	private $arr_config = array();
	
	/**
	 * 类实例对象
	 * @var object
	 */
	private static $obj_redis_cluster;
	
	/**
	 * 压缩内容使用的头信息
	 * @var string
	 */
	private $str_zip_header = 'ZIP##';
	
	/**
	 * 构造方法，初始化配置信息
	 * @param $arr_config = array(
	 * 		'map_type'		=> '缓存类型',
	 * 		'cache_type'	=> '缓存类型',
	 * 		'servers'		=> array(
	 * 			0 => 'redis cluster服务器配置信息，格式如：127.0.0.1:6379'
	 * 		)
	 * )
	 * @author chunyang.shu
	 * @date 2017-02-08
	 */
	public function __construct($config)
	{
		$this->arr_config = $config;
	}
	
	/**
	 * 析构方法，关闭连接
	 * @author chunyang.shu
	 * @date 2017-02-08
	 */
	public function __destruct()
	{
		$this->_close();
	}
	
	/**
	 * open的时候不做任何操作，连接在写的时候去判断
	 * User: yxt
	 */
	public function open( )
	{
		
	}
	
	/**
	 * 关闭连接
	 * @author chunyang.shu
	 * @date 2017-02-08
	 */
	public function close()
	{
		$this->_close();
	}
	
	/**
	 * 获取redis cluster实例对象
	 * @return false 获取失败    object 获取成功
	 * @author chunyang.shu
	 * @date 2017-02-08
	 */
	private function __get_redis_cluster_instance()
	{
		// 如果实例对象不存在，实例化对象
		if (!(self::$obj_redis_cluster instanceof RedisCluster))
		{
			$arr_redis_cluster_config = $this->arr_config['servers'];
			$arr_redis_cluster_config[] = $this->int_connect_timeout; // 连接超时时间
			$arr_redis_cluster_config[] = $this->int_query_timeout; // 查询超时时间
			$obj_redis_cluster = new RedisCluster(null, $arr_redis_cluster_config);
			if (!$obj_redis_cluster)
			{
				return false;
			}
			self::$obj_redis_cluster = $obj_redis_cluster;
		}
		
		// 返回数据
		return self::$obj_redis_cluster;
	}
	
	/**
	 * 设置key的值
	 * @param string $key 键
	 * @param string $value 值
	 * @param int $expire 有效期，默认是5分钟，如果设置的时间小于1s，则按照5分钟存，如果设置的时间大于25小时，也按照25小时存
	 * @param null $ex_flag
	 * @return true 表示设置成功    false 表示设置失败
	 * @author chunyang.shu
	 * @date 2017-02-08
	 */
	public function set($key, $value, $expire = 300, $ex_flag = null)
	{
		// 数据压缩
		$value = $this->_zip_value($value);
	
		// 处理有效期时间
		$expire = intval($expire);
		if($expire > 10800)
		{
			$expire = 10800;
		}
		if($expire < 1)
		{
			$expire = 300;
		}
		
		// 获取redis集群对象
		$obj_redis_cluster = $this->__get_redis_cluster_instance();
		
		// 设置key的值
		$result = false;
		if(is_object($obj_redis_cluster))
		{
			$result = $obj_redis_cluster->setex($key, $expire, $value);
		}
		
		// 返回结果
		return $result;
	}
	
	/**
	 * 从读库获取指定键的值，只支持单个key
	 * @param string $str_key 键
	 * @return false 表示获取失败    string 表示获取成功
	 * @author chunyang.shu
	 * @date 2017-02-08
	 */
	public function get($str_key)
	{
		// 获取redis集群对象
		$obj_redis_cluster = $this->__get_redis_cluster_instance();
		
		// 获取指定键的值
		$result = false;
		if (is_object($obj_redis_cluster))
		{
			$result = $obj_redis_cluster->get($str_key);
		}
		
		// 数据解压缩
		$result = $this->_unzip_value($result);
		
		// 返回结果
		return $result;
	}
	
	/**
	 * 从写库获取指定键的值，只支持单个key
	 * @param string $str_key 键
	 * @return false 表示获取失败    string 表示获取成功
	 * @author chunyang.shu
	 * @date 2017-02-08
	 */
	public function get_in_set($str_key)
	{
		return $this->get($str_key);
	}
	/**
	 * 删除指定的键
	 * @param string $str_key 键
	 * @return false 删除失败    true 删除成功
	 * @author chunyang.shu
	 * @date 2017-02-08
	 */
	public function delete( $str_key )
	{
		// 获取redis集群对象
		$obj_redis_cluster = $this->__get_redis_cluster_instance();
		
		// 删除指定的键
		$result = $obj_redis_cluster->del($str_key);
		
		// 返回结果
		return $result;
	}
	
	/**
	 * 添加键值信息
	 * @param string $key 键
	 * @param string $value 值
	 * @param int $expire 缓存过期时间
	 * @param null $ex_flag
	 * @return true 表示设置成功    false 表示设置失败
	 * @author chunyang.shu
	 * @date 2017-02-08
	 */
	public function add($key, $value, $expire = 0, $ex_flag = null)
	{
		return $this->set($key, $value, $expire, $ex_flag);
	
	}

    /**
     * 添加键值信息(不过期,不做任何处理)
     * @param string $key 键
     * @param string $value 值
     * @return true 表示设置成功    false 表示设置失败
     * @author jun li
     * @date 2017-08-11
     */
    public function setnoex($key, $value)
    {
        if ($key === '' || $value === '')
        {
            return false;
        }

        // 获取redis集群对象
        $obj_redis_cluster = $this->__get_redis_cluster_instance();

        // 设置key的值
        $result = false;
        if(is_object($obj_redis_cluster))
        {
            $result = $obj_redis_cluster->set($key, $value);
        }

        // 返回结果
        return $result;
    }

    /**
     * 从读库获取指定键的值(不过期 不处理)
     * @param string $str_key 键
     * @return false 表示获取失败    string 表示获取成功
     * @author jun li
     * @date 2017-08-011
     */
    public function getnoex($key)
    {
        if ($key === '')
        {
            return false;
        }

        // 获取redis集群对象
        $obj_redis_cluster = $this->__get_redis_cluster_instance();

        // 获取指定键的值
        $result = false;
        if (is_object($obj_redis_cluster))
        {
            $result = $obj_redis_cluster->get($key);
        }

        return $result;
    }



	public function last_error_desc()
	{
		
	}
	
	public function get_type()
	{
		
	}
	
	/**
	 * 关闭连接
	 * @author chunyang.shu
	 * @date 2017-02-08
	 */
	private function _close()
	{
		if (is_object(self::$obj_redis_cluster))
		{
			self::$obj_redis_cluster->close();
		}
		self::$obj_redis_cluster = null;
	}
	
	/**
	 * 对字符串进行压缩，当字符串小于256，则不进行压缩
	 * @param $value
	 * @return string
	 */
	private function _zip_value($value)
	{
		if (!is_array($value) && empty($value))
		{
			return $value;
		}
		$value = serialize($value);
		$len = strlen($value);
		if ($len > 256 && $this->kv_zip_enabled === true )
		{
			$zip_value = gzcompress($value);
			return  $this->zip_header.$zip_value;
		}
		return $value;
	}
	
	/**
	 * 对字符串进行解压
	 * @param $value
	 * @return string
	 */
	private function _unzip_value($value)
	{
		if (empty($value))
		{
			return $value;
		}
	
		if ($this->kv_zip_enabled === false)
		{
			return unserialize($value);
		}
	
		$zip_flag = substr($value,0,5);
		if ($zip_flag == $this->zip_header)
		{
			$zip_value = substr($value,5);
			return unserialize(gzuncompress($zip_value));
		}
		return unserialize($value);
	}
}